﻿
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;

namespace Bot.Domain.Report
{
    /// <summary>
    /// 报表基础包
    /// </summary>
    /// <typeparam name="TReportItem"></typeparam>
    /// <typeparam name="TViewInfo"></typeparam>
    /// <typeparam name="TReportEntity"></typeparam>

    public class BasicWrap<TReportItem, TViewInfo, TReportEntity>
        where TReportItem : BaseReportInfoItem, new()
        where TViewInfo : BaseReportInfo<TReportItem>, new()
    {
        protected const int hournum = 24;
        //[[1 3] [2 10] [3 9] [100 200]] => [[1 10] [100 200]]
        public static IEnumerable<T> MergeOverlap<T>(IEnumerable<T> source, Func<T, T, bool> isOverlap, Func<T, T, T> merge)
        {
            using (var it = source.GetEnumerator())
            {
                if (it.MoveNext())
                {
                    T prev = it.Current;

                    while (it.MoveNext())
                    {
                        //不变式： prev是需要合并的range, it.current是下一项
                        T current = it.Current;
                        if (isOverlap(prev, current))
                        {
                            prev = merge(prev, current);
                        }
                        else
                        {
                            yield return prev;
                            prev = current;
                        }
                    }

                    yield return prev;
                }
            }
        }

        // 这里的逻辑处理改为，不会出现大于100%的情况，只有分母为0的时候，值就是100%
        protected static double CalcPercent(double value1, double value2)
        {
            if (value1 != 0 && value2 == 0)
            {
                return 100;
            }
            else if (value1 == 0 && value2 == 0)
            {
                return 0;
            }
            else
            {
                double revalue = Math.Round((value1 * 100.00) / value2, 2);
                return revalue > 100 ? 100 : revalue;
            }
        }

        protected static double CalcAvg(double value1, double value2, int numOfDecimal = 2)
        {
            return value2 <= 0 ? 0 : Math.Round(value1 / value2, numOfDecimal);
        }

        protected static double CalcTwoPoint(double value)
        {
            return Math.Round(value, 2);
        }

        protected static double CalcFloor(double value)
        {
            return Math.Floor(value);
        }

        // 直接去掉毫秒
        protected static TimeSpan CutTimeSpan(TimeSpan ts)
        {
            return TimeSpan.Parse(ts.ToDateTimeString());
        }

        //calcuate the day of week count
        protected static int[] CountDays(DateTime start, DateTime end)
        {
            int[] numDays = new int[7];
            for (DateTime dt = start.Date; dt <= end.AddMinutes(-1).Date; dt = dt.AddDays(1))
            {
                numDays[(int)dt.DayOfWeek]++;
            }

            return numDays;
        }

        protected static int GetDays(DateTime start, DateTime end)
        {
            int nums = 0;
            for (DateTime dt = start.Date; dt <= end.AddMinutes(-1).Date; dt = dt.AddDays(1))
            {
                nums++;
            }

            return nums;
        }

        // calcuate the weeks in daterange use for 24_7 total
        protected static double GetWeeksInDateRange(DateTime start, DateTime end)
        {
            int days = GetDays(start, end);
            return days / 7.0;
        }

        protected static TViewInfo GetInfoByTime(SearchCriteria search, TReportEntity entityInfo, Func<TViewInfo, TReportEntity, SearchCriteria, TViewInfo> funcByTime, Func<TViewInfo, TReportEntity, SearchCriteria, TViewInfo> funcByTime24_7, Func<TViewInfo, TReportEntity, SearchCriteria, TViewInfo> funcByTime48Half)
        {
            var result = new TViewInfo();
            switch (search.timeUnit)
            {
                case EnumTimeIntervalType.Hourly:
                    result = GetInfoByTimeWithHourly(search, entityInfo, funcByTime);
                    break;
                case EnumTimeIntervalType.Daily:
                    result = GetInfoByTimeWithDaily(search, entityInfo, funcByTime);
                    break;
                case EnumTimeIntervalType.Weekly:
                    result = GetInfoByTimeWithWeekly(search, entityInfo, funcByTime);
                    break;
                case EnumTimeIntervalType.Monthly:
                    result = GetInfoByTimeWithMonthly(search, entityInfo, funcByTime);
                    break;
                case EnumTimeIntervalType.Distribution24_7Hour:
                    result = GetInfoByTimeWith24_7Distribution(search, entityInfo, funcByTime24_7);
                    break;
                case EnumTimeIntervalType.Distribution48HalfHour:
                    result = GetInfoByTimeWith48HalfHourDistribution(search, entityInfo, funcByTime48Half);
                    break;
            }
            return result;
        }

        protected static TViewInfo GetInfoByTimeWithHourly(SearchCriteria search, TReportEntity entityInfo, Func<TViewInfo, TReportEntity, SearchCriteria, TViewInfo> push)
        {
            TViewInfo result = new TViewInfo();
            result.dataType = EnumReportDataType.DataByTime;
            result.dataList = new List<TReportItem>();
            //for (int i = 0; i < Math.Ceiling(((TimeSpan)(search.endDate - search.startDate)).TotalHours); i++)
            int i = 0;
            for (DateTime dt = new DateTime(search.startDate.Year, search.startDate.Month, search.startDate.Day, search.startDate.Hour, 0, 0); dt <= search.endDate.AddMinutes(-1); dt = dt.AddHours(1))
            {
                //local Time
                DateTime start = search.startDate.AddHours(i);
                DateTime end = start.AddHours(1);

                if (i == 0)
                {
                    end = new DateTime(end.Year, end.Month, end.Day, end.Hour, 0, 0);
                }
                else if (i > 0)
                {
                    start = new DateTime(start.Year, start.Month, start.Day, start.Hour, 0, 0);
                    end = new DateTime(end.Year, end.Month, end.Day, end.Hour, 0, 0);
                }

                if (end > search.endDate)
                {
                    end = search.endDate;
                }

                var item = new TReportItem();

                // local Time
                item.startTime = start.ToString();
                item.startTimeDate = start;
                item.endTime = end.ToString();
                item.endTimeDate = end;
                // UTC Time
                item.LocalstrartTime = start;
                item.LocalendTime = end;

                string toHour = start.AddMinutes(60).ToString("HH") == "00" ? "24" : start.AddMinutes(60).ToString("HH");
                item.xAxisName = start.ToString(search.dateFormat) + Environment.NewLine + start.ToString("HH") + ":00 ~ " + toHour + ":00";
                item.tableRowName = item.xAxisName;

                result.dataList.Add(item);
                i++;
            }
            result = push(result, entityInfo, search);
            return result;
        }

        protected static TViewInfo GetInfoByTimeWithDaily(SearchCriteria search, TReportEntity entityInfo, Func<TViewInfo, TReportEntity, SearchCriteria, TViewInfo> push)
        {
            //TN result = new BaseReportInfo<TI>() ;
            TViewInfo result = new TViewInfo();
            result.dataType = EnumReportDataType.DataByTime;
            result.dataList = new List<TReportItem>();
            //for (int i = 0; i < Math.Ceiling(((TimeSpan)(search.endDate - search.startDate)).TotalDays); i++)
            int i = 0;
            for (DateTime dt = search.startDate.Date; dt <= search.endDate.AddMinutes(-1).Date; dt = dt.AddDays(1))
            {
                //local Time
                DateTime start = search.startDate.AddDays(i);
                DateTime end = start.AddDays(1);

                if (i == 0)
                {
                    end = end.Date;
                }
                else if (i > 0)
                {
                    start = start.Date;
                    end = end.Date;
                }

                if (end > search.endDate)
                {
                    end = search.endDate;
                }


                var item = new TReportItem();

                // local Time
                item.startTime = start.ToString();
                item.endTime = end.ToString();

                item.startTimeDate = start;
                item.endTimeDate = end;
                // UTC Time
                item.LocalstrartTime = start;
                item.LocalendTime = end;

                item.xAxisName = start.ToString("MMM dd", CultureInfo.GetCultureInfo("en-US"));
                item.tableRowName = start.ToString(search.dateFormat);

                result.dataList.Add(item);
                i++;
            }
            result = push(result, entityInfo, search);
            return result;
        }

        protected static TViewInfo GetInfoByTimeWithWeekly(SearchCriteria search, TReportEntity entityInfo, Func<TViewInfo, TReportEntity, SearchCriteria, TViewInfo> push)
        {
            // 第一个周日
            DateTime firstWeekSunday = search.startDate.AddDays(7 - (int)search.startDate.DayOfWeek).Date;
            // 最后一个周日
            DateTime latestWeekSunday = search.endDate.AddMinutes(-1).AddDays(7 - (int)search.endDate.AddMinutes(-1).DayOfWeek).Date;

            TViewInfo result = new TViewInfo();
            result.dataType = EnumReportDataType.DataByTime;
            result.dataList = new List<TReportItem>();

            if (firstWeekSunday <= search.endDate.Date)
            {
                for (int i = 0; latestWeekSunday >= firstWeekSunday.AddDays(i * 7).Date; i++)
                {
                    var item1 = new TReportItem();
                    string displayNameStartStr = string.Empty;
                    string displayNameEndStr = string.Empty;
                    //Local Date Time
                    // 第一个星期开始时间要变
                    if (i == 0)
                    {
                        item1.startTime = search.startDate.ToString();
                        item1.startTimeDate = search.startDate;
                        item1.LocalstrartTime = search.startDate;
                        displayNameStartStr = search.startDate.ToString(search.dateFormat);
                    }
                    else
                    {
                        item1.startTime = firstWeekSunday.AddDays((i - 1) * 7).ToString();
                        item1.startTimeDate = firstWeekSunday.AddDays((i - 1) * 7);
                        item1.LocalstrartTime = firstWeekSunday.AddDays((i - 1) * 7);
                        displayNameStartStr = firstWeekSunday.AddDays((i - 1) * 7).ToString(search.dateFormat);
                    }

                    // 最后一个星期结束时间要变，并且不能format
                    if (search.endDate.Date < firstWeekSunday.AddDays(i * 7).Date)
                    {
                        item1.endTime = search.endDate.ToString();
                        item1.endTimeDate = search.endDate;
                        item1.LocalendTime = search.endDate;
                        // 最后一周结束时间为选择的结束时间
                        item1.xAxisName = search.endDate.AddMinutes(-1).ToString("MMM dd", CultureInfo.GetCultureInfo("en-US"));
                        displayNameEndStr = search.endDate.AddMinutes(-1).ToString(search.dateFormat);
                    }
                    else
                    {
                        item1.endTime = firstWeekSunday.AddDays(i * 7).ToString();
                        item1.endTimeDate = firstWeekSunday.AddDays(i * 7);
                        item1.LocalendTime = firstWeekSunday.AddDays(i * 7);
                        // displayTime是周六
                        item1.xAxisName = firstWeekSunday.AddDays(i * 7 - 1).ToString("MMM dd", CultureInfo.GetCultureInfo("en-US"));
                        displayNameEndStr = firstWeekSunday.AddDays(i * 7 - 1).ToString(search.dateFormat);
                    }

                    //item1.tableRowName = displayNameStartStr + " ~ " + Environment.NewLine + displayNameEndStr;
                    item1.tableRowName = displayNameStartStr + " ~ "  + displayNameEndStr;

                    result.dataList.Add(item1);
                }
            }
            else
            {
                //在一个星期的范围之内
                var item = new TReportItem();
                //Local Date Time
                item.startTime = search.startDate.ToString();
                item.startTimeDate = search.startDate;
                item.endTime = search.endDate.ToString();
                item.endTimeDate = search.endDate;

                item.LocalstrartTime = search.startDate;
                item.LocalendTime = search.endDate;

                item.xAxisName = search.endDate.AddMinutes(-1).ToString("MMM dd", CultureInfo.GetCultureInfo("en-US"));
                item.tableRowName = search.startDate.ToString(search.dateFormat) + " ~ " + search.endDate.AddMinutes(-1).ToString(search.dateFormat);

                result.dataList.Add(item);
            }
            result = push(result, entityInfo, search);
            return result;
        }

        protected static TViewInfo GetInfoByTimeWithMonthly(SearchCriteria search, TReportEntity entityInfo, Func<TViewInfo, TReportEntity, SearchCriteria, TViewInfo> push)
        {
            TViewInfo result = new TViewInfo();
            result.dataType = EnumReportDataType.DataByTime;
            result.dataList = new List<TReportItem>();
            int totalMonth = search.endDate.AddMinutes(-1).Year * 12 + search.endDate.AddMinutes(-1).Month - search.startDate.Year * 12 - search.startDate.Month + 1;

            for (int i = 0; i < totalMonth; i++)
            {
                DateTime startMonth = search.startDate.AddMonths(i);
                DateTime endMonth = startMonth.AddMonths(1);

                var item = new TReportItem();

                if (i == 0)
                {
                    item.startTime = search.startDate.ToString();
                    item.startTimeDate = search.startDate;
                    item.LocalstrartTime = search.startDate;
                }
                else
                {
                    item.startTimeDate = new DateTime(startMonth.Year, startMonth.Month, 1);
                    item.startTime = item.startTimeDate.ToString();
                    item.LocalstrartTime = new DateTime(startMonth.Year, startMonth.Month, 1);
                }

                if (i == totalMonth - 1)
                {
                    item.endTime = search.endDate.ToString();
                    item.endTimeDate = search.endDate;
                    item.LocalendTime = search.endDate;
                }
                else
                {
                    item.endTimeDate = new DateTime(endMonth.Year, endMonth.Month, 1);
                    item.endTime = item.endTimeDate.ToString();

                    item.LocalendTime = new DateTime(endMonth.Year, endMonth.Month, 1);
                }

                item.xAxisName = startMonth.ToString("MMM", CultureInfo.GetCultureInfo("en-US"));
                item.tableRowName = startMonth.ToString("yyyy-MM");

                result.dataList.Add(item);
            }
            result = push(result, entityInfo, search);
            return result;
        }

        protected static TViewInfo GetInfoByTimeWith24_7Distribution(SearchCriteria search, TReportEntity entityInfo, Func<TViewInfo, TReportEntity, SearchCriteria, TViewInfo> push)
        {
            TViewInfo result = new TViewInfo();
            result.dataType = EnumReportDataType.DataByTimeWith24_7;
            result.dataList = new List<TReportItem>();
            for (int i = 0; i < hournum * 7; i++)
            {
                TReportItem item = new TReportItem();
                string weekstr = ((DayOfWeek)(i / hournum)).ToString().Substring(0, 3);
                item.xAxisName = string.Format("{2}. " + Environment.NewLine + "{0:00}:00 - {1:00}:00", i % hournum, i % hournum + 1, weekstr);
                item.tableRowName = item.xAxisName;
                item.IndexNum = i;
                result.dataList.Add(item);
            }

            result.dataByTimeWithDistribution = new List<BaseItemByTimeWithDistribution<TReportItem>>();
            foreach (string weekname in System.Enum.GetNames(typeof(DayOfWeek)))
            {
                result.dataByTimeWithDistribution.Add(new BaseItemByTimeWithDistribution<TReportItem>() { dayOfWeek = weekname, dataByTimeList = new List<TReportItem>() });
            }

            result = push(result, entityInfo, search);
            return result;
        }

        protected static TViewInfo GetInfoByTimeWith48HalfHourDistribution(SearchCriteria search, TReportEntity entityInfo, Func<TViewInfo, TReportEntity, SearchCriteria, TViewInfo> push)
        {
            TViewInfo result = new TViewInfo();
            result.dataType = EnumReportDataType.DataByTimeWith48HalfHour;
            result.dataList = new List<TReportItem>();
            for (int i = 0; i < hournum * 2; i++)
            {
                TReportItem item = new TReportItem();
                int hourIndex = i / 2;
                if (i % 2 == 0)
                {
                    item.xAxisName = string.Format("{0:00}:00 - {0:00}:30", hourIndex);
                }
                else
                {
                    item.xAxisName = string.Format("{0:00}:30 - {1:00}:00", hourIndex, hourIndex + 1);
                }

                item.tableRowName = item.xAxisName;
                item.IndexNum = i;
                result.dataList.Add(item);
            }
            result = push(result, entityInfo, search);
            return result;
        }

        protected static NewExportCSVData GetExprotCSVData(SearchCriteria search, TViewInfo Info, List<string> fieldList)
        {
            var namePreChar = string.Empty;
            if (search.timeUnit == EnumTimeIntervalType.Distribution24_7Hour || search.timeUnit == EnumTimeIntervalType.Distribution48HalfHour)
            {
                namePreChar = "Avg. ";
            }
            else
            {
                Info.dataList = Info.dataList.OrderByDescending(c => c.LocalstrartTime).ToList();
            }
            NewExportCSVData result = new NewExportCSVData(GetReportName(search.action), new List<NewCSVColumn>(), new DataTable());

            result.columns.Add(new NewCSVColumn(GetDimensionName(search.dimensionType), GetDimensionName(search.dimensionType), true));

            //result.source.Columns.Add(GetDimensionName(search.dimensionType), typeof(string));
            foreach (string fieldName in fieldList)
            {
                if (fieldName.StartsWith("Avg", StringComparison.OrdinalIgnoreCase) || fieldName.StartsWith("Max", StringComparison.OrdinalIgnoreCase))
                {
                    result.columns.Add(new NewCSVColumn(fieldName, fieldName, true));
                }
                else
                {
                    result.columns.Add(new NewCSVColumn(namePreChar + fieldName, fieldName, true));
                }
                // result.source.Columns.Add(namePreChar+fieldName, typeof(string));
            }

            foreach (NewCSVColumn column in result.columns)
            {
                result.source.Columns.Add(column.header, typeof(string));
            }

            if (search.timeUnit == EnumTimeIntervalType.Distribution24_7Hour)
            {
                Info.dataByTimeWithDistribution.SelectMany(t => t.dataByTimeList).ToList().ForEach(c =>
                {
                    DataRow row = result.source.NewRow();
                    row[0] = c.tableRowName.Replace(Environment.NewLine, " ");
                    for (int i = 0; i < fieldList.Count; i++)
                    {
                        row[i + 1] = c.GetValue(Info.FieldList.IndexOf(fieldList[i]));
                    }
                    result.source.Rows.Add(row);
                });
            }
            else
            {
                DataRow totalRow = result.source.NewRow();
                totalRow[0] = "Total";
                for (int i = 0; i < fieldList.Count; i++)
                {
                    totalRow[i + 1] = Info.GetValue(Info.FieldList.IndexOf(fieldList[i]));
                }
                result.source.Rows.Add(totalRow);

                foreach (TReportItem item in Info.dataList)
                {
                    DataRow row = result.source.NewRow();
                    row[0] = item.tableRowName.Replace(Environment.NewLine, " ");
                    for (int i = 0; i < fieldList.Count; i++)
                    {
                        row[i + 1] = item.GetValue(Info.FieldList.IndexOf(fieldList[i]));
                    }

                    result.source.Rows.Add(row);
                }

            }

            return result;
        }

        private static string GetReportName(EnumNewReportActionType type)
        {
            string str = type.ToString() + " ";
            switch (type)
            {
                case EnumNewReportActionType.RealTime:
                    break;
                case EnumNewReportActionType.ChatVolume:
                    str = "Chat Volume ";
                    break;
                case EnumNewReportActionType.ChatSource:
                    str = "Chat Source ";
                    break;
                case EnumNewReportActionType.Queue:
                    str = "Queue ";
                    break;
                case EnumNewReportActionType.WaitTime:
                    str = "Wait Time ";
                    break;
                case EnumNewReportActionType.ChatTransfer:
                    str = "Chat Transfer ";
                    break;
                case EnumNewReportActionType.Availability:
                    str = "Availability ";
                    break;
                case EnumNewReportActionType.Workload:
                    str = "Work Load ";
                    break;
                case EnumNewReportActionType.Efficiency:

                    break;
                case EnumNewReportActionType.Rating:
                    str = "Rating ";
                    break;
                case EnumNewReportActionType.PostChatSurvey:
                    str = "Post Chat Survey of ";
                    break;
                case EnumNewReportActionType.PreChatSurvey:
                    str = "Pre-Chat Survey of ";
                    break;
                case EnumNewReportActionType.Wrapup:
                    str = "Wrap-Up ";
                    break;
                case EnumNewReportActionType.ManualInvitation:
                    str = "Manual Invitation ";
                    break;
                case EnumNewReportActionType.AutoInvitation:
                    str = "Auto Invitation ";
                    break;
                case EnumNewReportActionType.OfflineMessage:
                    str = "Offline Message ";
                    break;
                case EnumNewReportActionType.CannedMessage:
                    str = "Canned Message Details of ";
                    break;
                case EnumNewReportActionType.TrafficSource:
                    break;
                case EnumNewReportActionType.Performance:
                    str = "Agent Performance ";
                    break;
                case EnumNewReportActionType.ChatbotChats:
                    str = "Bot Chats of ";
                    break;
                case EnumNewReportActionType.ChatbotResponse:
                    str = "Bot Answers of ";
                    break;
                case EnumNewReportActionType.ChatbotHighConfidenceResponse:
                    str = "Bot High Confidence Answers of ";
                    break;
                case EnumNewReportActionType.ChatbotRating:
                    str = "Bot Rating of ";
                    break;
                case EnumNewReportActionType.ChatbotAgent:
                    str = "Bot Bot&Agent of ";
                    break;
                case EnumNewReportActionType.UsageDetailsByIntent:
                    str = "UsageDetailsByIntents ";
                    break;
                default:
                    break;
            }
            return str;
        }

        private static string GetDimensionName(EnumDimensionType type)
        {
            string str = string.Empty;
            switch (type)
            {
                case EnumDimensionType.ByTime:
                    str = "Time";
                    break;
                case EnumDimensionType.ByDepartment:
                    str = "Department";
                    break;
                case EnumDimensionType.ByAgent:
                    str = "Agent";
                    break;
                case EnumDimensionType.ByCampaign:
                    str = "Campaign";
                    break;
                case EnumDimensionType.ByVisitorSegment:
                    str = "Visitor Segment";
                    break;
                case EnumDimensionType.RequestPage:
                    str = "Request Page";
                    break;
                case EnumDimensionType.ChangeLog:
                    break;
                case EnumDimensionType.CannedMessage:
                    str = "Canned Message Name";
                    break;
                case EnumDimensionType.ByInvitation:
                    str = "Invitation Name";
                    break;
                case EnumDimensionType.ChatbotChats:
                case EnumDimensionType.ChatbotAnswers:
                case EnumDimensionType.ChatbotHightFidenceAnswers:
                    str = "Time";
                    break;
                default:
                    break;
            }        

            return str;
        }

        protected static string GetTableRowName(bool ifEncode, string fieldName)
        {
           // return ifEncode ? Microsoft.Security.Application.Encoder.HtmlEncode(fieldName) : fieldName;
            return fieldName;
        }

    }

    public static class WrapHelper
    {
        public static TimeSpan Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, TimeSpan> selector)
        {
            return source.Select(selector).Aggregate(TimeSpan.Zero, (t1, t2) => t1 + t2);
        }

        public static IEnumerable<TSource> WrapWhere<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> perdicate)
        {
            foreach (var item in source)
            {
                if (perdicate(item))
                {
                    yield return item;
                }
                //                yield return 
            }
        }

        public static string ToDateTimeString(this TimeSpan _timespan)
        {
            _timespan = _timespan < TimeSpan.Zero ? TimeSpan.Zero : _timespan;

            if (_timespan.Days > 0)
            {
                return string.Format("{0}.{1:00}:{2:00}:{3:00}", _timespan.Days, _timespan.Hours, _timespan.Minutes, _timespan.Seconds);
            }
            else
            {
                return string.Format("{0:00}:{1:00}:{2:00}", _timespan.Hours, _timespan.Minutes, _timespan.Seconds);
            }
        }

        //public static string GetEncodeStr(string fieldName)
        //{
        //    return Microsoft.Security.Application.Encoder.HtmlEncode(fieldName);
        //}

        //public static string GetDecodeStr(string fieldName)
        //{
        //    return Microsoft.Security.Application.de
        //}
    }

    public class BaseReportInfo<T> where T : BaseReportInfoItem
    {
        [JsonIgnore]
        public EnumReportDataType DataType { get { return dataType; } }
        public virtual IList<T> DataList { get { return dataList; } }

        public BaseReportInfo()
        {
            dataList = new List<T>();
        }

        [JsonIgnore]
        public EnumReportDataType dataType;

        [JsonIgnore]
        public IList<T> dataList;//public IList<T> dataList;
        [JsonIgnore]
        public IList<BaseItemByTimeWithDistribution<T>> dataByTimeWithDistribution;

        public virtual string GetValue(int i)
        {
            return string.Empty;
        }

        [JsonIgnore]
        public virtual List<string> FieldList { get; set; }
    }

    public class CustomDateTimeConverter : DateTimeConverterBase
    {
        private double DateTimeToUnix(DateTime d)
        {
            return (d - (new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc))).TotalMilliseconds;
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType != JsonToken.Integer)
            {
                throw new Exception(string.Format("date format error"));
            }
            var ticks = (long)reader.Value;
            var date = new DateTime(1970, 1, 1);
            date = date.AddSeconds(ticks);
            return date;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            writer.WriteValue(DateTimeToUnix((DateTime)value));
        }
    }
    public class DataTimeConvert : JsonConverter
    {
        public DataTimeConvert() { }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
        public override bool CanConvert(Type objectType)
        {
            return true;
        }
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            if (value == null)
            {
                writer.WriteNull();
                return;
            }

            DateTime dateTimeValue = Convert.ToDateTime(value);
            
            writer.WriteValue(dateTimeValue.ToString("yyyy-MM-dd HH:mm:ss"));
        }
    }

    public class BaseReportInfoItem
    {
        // 表格第一列的显示,属于3个tab公用的字段,其实也就是分组后的组名
        [JsonProperty(PropertyName = "Time")]
        public string tableRowName; //public string displayName;
        [JsonIgnore]                           // 用于BY TIME的X轴显示
        [JsonProperty(PropertyName = "XAxisName")]
        public string xAxisName; //public string displayTime;
        [JsonIgnore]
        [JsonProperty(PropertyName = "FieldId")]
        public int fieldId;  //dimensionId
        //[JsonIgnore]
        //[JsonProperty(PropertyName = "StartTime")]
        [JsonConverter(typeof(DataTimeConvert))]
        public string startTime;
        //[JsonIgnore]
        //[JsonProperty(PropertyName = "EndTime")]
        [JsonConverter(typeof(DataTimeConvert))]
        public string endTime;
        [JsonIgnore]
        [JsonProperty(PropertyName = "StartTimeDate")]
        [JsonConverter(typeof(CustomDateTimeConverter))]
        public DateTime startTimeDate;
        [JsonIgnore]
        [JsonProperty(PropertyName = "EndTimeDate")]
        [JsonConverter(typeof(CustomDateTimeConverter))]
        public DateTime endTimeDate;
        [JsonIgnore]
        public DateTime LocalstrartTime;
        [JsonIgnore]
        public DateTime LocalendTime;
        [JsonIgnore]
        public int IndexNum;

        public virtual string GetValue(int i)
        {
            return string.Empty;
        }

        protected double CalcAvg(double value1, double value2, int numOfDecimal = 2)
        {
            return value2 <= 0 ? 0 : Math.Round(value1 / value2, numOfDecimal);
        }

        protected double CalcTwoPoint(double value)
        {
            return Math.Round(value, 2);
        }

    }

    public class BaseItemByTimeWithDistribution<T> where T : BaseReportInfoItem
    {
        public string dayOfWeek;

        public IList<T> dataByTimeList;
    }

    //public enum EnumTimeIntervalType
    //{
    //    Hourly = 0,
    //    Daily = 1,
    //    Weekly = 2,
    //    Monthly = 3,
    //    Distribution24_7Hour = 4,
    //    Distribution48HalfHour = 5
    //}
    public enum EnumReportDataType
    {
        DataByDimension = 0,
        DataByTime = 0,
        DataByTimeWith24_7 = 1,
        DataByTimeWith48HalfHour = 2
    }
    public class SearchCriteria
    {
        public EnumNewReportActionType action;
        public bool ifWrapUpAdvanced;
        [JsonIgnore]
        public EnumOperatorStatus operatorStatus;
        public Guid segmentId;
        [JsonIgnore]
        public int autoInvitationId;
        public int conversionId;
        public string dateFormat;
        public Guid categoryId;
        public Guid codePlanId;
        public int operatorId;
        public Guid departmentId;
        public EnumFilterType filterType;
        public EnumDimensionType dimensionType;//报表的统计维度，对应的报表的Tab页
        public string channel;
        [JsonIgnore]
        public DateTime utcEndDate;
        [JsonIgnore]
        public DateTime utcStartDate;
        public DateTime endDate;
        public DateTime startDate;
        public EnumDateRangeType dateRange;
        public EnumTimeIntervalType timeUnit;
        public int siteId;
        public string filterStr;
        public Guid botId;
        [JsonIgnore]
        public TimeSpan timeOffset;
        public string SummaryChannel { get; set; } = "livechat";

        public SearchCriteria()
        {

        }
        public SearchCriteria(EnumDimensionType dimensionType, EnumFilterType filterType)
        {
            this.dimensionType = dimensionType;
            this.filterType = filterType;
            this.channel = "";
        }
    }
    public enum EnumNewReportActionType
    {
        RealTime = 1,
        ChatVolume = 2,
        ChatSource = 3,
        Queue = 4,
        WaitTime = 5,
        ChatTransfer = 6,
        Availability = 7,
        Workload = 8,
        Efficiency = 9,
        Rating = 10,
        PostChatSurvey = 11,
        PreChatSurvey = 12,
        Wrapup = 13,
        ManualInvitation = 14,
        AutoInvitation = 15,
        OfflineMessage = 16,
        CannedMessage = 17,
        TrafficSource = 18,
        Performance = 19,
        chatbot = 20,
        Conversion = 21,
        ChatbotChats=22,
        ChatbotResponse=23,
        ChatbotHighConfidenceResponse=24,
        ChatbotRating=25,
        ChatbotAgent=26,
        ChatbotLast7DaysDaily=27,
        UsageDetailsByIntent=28,
        UsageDetailsByTime = 29,
    }
    public enum EnumOperatorStatus
    {
        enumLoggedIn = -2,
        enumTotalAway = -1,
        enumOnline = 0,
        enumAway = 1,
        enumOffline = 2,
        enumUnknow = 3,
        enumChatBegin = 4,
        enumChatEnd = 5,
        enumCustomAwayStatusBegin = 100
    }

    public enum EnumFilterType
    {
        Site = 0,
        Department = 1,
        Agent = 2,
        Campaign = 3,
        Category = 4,
        VisitorSegment = 5,
        Conversion = 6,
        Bot=7,
        channelAccount=8,
        chatFilterType=9,
    }
    public enum EnumDimensionType
    {
        ByWebSite = -1,
        ByTime = 0,
        ByDepartment = 1,
        ByAgent = 2,
        ByCampaign = 3,
        ByVisitorSegment = 4,
        RequestPage = 5,
        ChangeLog = 6,
        Survey = 7,
        ByInvitation = 8,
        ByQueue = 9,
        CannedMessage = 10,
        ChatbotChats = 11,
        ChatbotAnswers = 12,
        ChatbotHightFidenceAnswers = 13,
        ByConversionAction = 14,
        ConversionList = 15,
    }
    public enum EnumDateRangeType
    {
        Today = 0,
        Yesterday = 1,
        ThisWeek = 2,
        LastWeek = 3,
        Last7Days = 4,
        Last14Days = 5,
        ThisMonth = 6,
        Last30Days = 7,
        LastMonth = 8,
        Custom = 9,
        SevenDays=10
    }
    public enum EnumTimeIntervalType
    {
        Daily = 0,
        Weekly = 1,
        Monthly = 2,
        HalfHourly = 3,
        Hourly = 4,
        Distribution24_7Hour = 5,
        Distribution48HalfHour = 6
    }

    public enum DisplayType
    {
          Day=0,
          Week=1,
          Month=2
    }


    //public class BaseReportInfoItem
    //{
    //    public string startTime { get; set; }
    //    public DateTime startTimeDate { get; set; }
    //    public string endTime { get; set; }
    //    public DateTime endTimeDate { get; set; }
    //    // UTC Time
    //    public DateTime LocalstrartTime { get; set; }
    //    public DateTime LocalendTime { get; set; }
    //    public string xAxisName { get; set; }
    //    public string tableRowName { get; set; }
    //    public int IndexNum { get; set; }
    //}
    //public class BaseReportInfo<T> where T : class
    //{
    //    public EnumReportDataType dataType { get; set; }
    //    public List<T> dataList { get; set; }
    //}

}